package ifile

import (
	"errors"
	"fmt"
	"gitee.com/bobo-rs/idea-space-framework/pkg/encrypt"
	"github.com/gogf/gf/v2/os/gtime"
	"math/rand"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"time"
)

// NormalizePath 规格化路径
func NormalizePath(path string) string {
	// 如果是Windows系统，确保路径使用反斜杠
	if runtime.GOOS == "windows" {

		return filepath.FromSlash(path)
	}

	// （如Linux或macOS），确保路径使用正斜杠 如果是Linux或其他UNIX-like系统，保持原样或转换为正斜杠（如果需要）
	return filepath.ToSlash(path)
}

// IsWindowsPath 检查路径字符串是否使用Windows风格的路径分隔符
func IsWindowsPath(path string) bool {
	return strings.Contains(path, `\`)
}

// RootPath 获取当前项目根目录
func RootPath() (string, error) {
	cmd, err := os.Getwd()
	if err != nil {
		return "", err
	}
	// 当前执行目录
	currentCmd := cmd
	// 循环查找go.mod
	for {
		// 检查当前目录是否含有go.mod文件
		if _, err = os.Stat(filepath.Join(cmd, `go.mod`)); err == nil {
			return cmd, nil
		}
		// 到了根目录
		if IsDriveLetterRoot(cmd) {
			break
		}

		// 继续向上遍历父目录
		cmd = filepath.Dir(cmd)
	}
	// 返回当前执行目录
	return currentCmd, nil
}

// MustRootPath 获取当前项目根目录
func MustRootPath() string {
	path, _ := RootPath()
	if len(path) == 0 {
		// 编译后的执行没有go.mod文件，则默认相关目录
		return `.`
	}
	return path
}

// MustResourcePath 获取资源静态目录-绝对
func MustResourcePath(paths ...string) string {
	return MustRootPath() + RelaResourcePath(paths...)
}

// MustUploadPath 获取并设置上传目录
func MustUploadPath(paths ...string) string {
	return MustResourcePath() + RelaUploadPath(paths...)
}

// RelaUploadPath 相对设置上传目录
func RelaUploadPath(paths ...string) string {
	dirSep := DirSeparator()
	uploadsPath := dirSep + `uploads`
	if len(paths) > 0 {
		path := NormalizePath(paths[0])
		uploadsPath += fmt.Sprintf(`%s%s`, dirSep, strings.TrimPrefix(strings.TrimPrefix(path, dirSep), `uploads`+dirSep))
	}
	return uploadsPath
}

// RelaResourcePath 相对资源静态目录
func RelaResourcePath(paths ...string) string {
	dirSep := DirSeparator()
	resourcePath := dirSep + `resource`
	if len(paths) > 0 {
		resourcePath += fmt.Sprintf(`%s%s`, dirSep, strings.TrimPrefix(NormalizePath(paths[0]), dirSep))
	}
	return resourcePath
}

// SuppIndicator 补充相对路径指示符（.）
func SuppIndicator(path string) string {
	// 路径长度索引
	var (
		count = len(path)
		index = 3 // 默认完整路径：/root/www 或 C:\www以及其他相对地址
	)
	// 路径为空
	if count == 0 {
		return path
	}

	// 路径小于3已到根目录，类似window：C:\和Linux：/
	if count < 3 {
		index = count
	}

	// 截取根前缀验证是否根目录或者已经是相对地址
	dirPrefix := path[:index]
	if strings.Contains(dirPrefix, `.`) || IsDriveLetterRoot(dirPrefix) {
		// 根目录或完整相对目录直接返回
		return path
	}

	// 把路径地址转换成Linux风格路径，并截取第一个字符验证是否已是相对路径
	relaDir := filepath.ToSlash(string(dirPrefix[0]))
	if relaDir != `/` {
		// 缺少当前目录分割符，补充分割符
		path = DirSeparator() + path
	}

	// 补充当前目录指示符
	return `.` + path
}

// IsDriveLetterRoot 验证是系统根目录
func IsDriveLetterRoot(path string) bool {
	// windows系统
	re := regexp.MustCompile(`^[a-zA-Z]:\\$`)
	if path == `/` || re.MatchString(path) {
		return true
	}
	return false
}

// DirSeparator 路径分割符
func DirSeparator() string {
	if runtime.GOOS == "windows" {
		return `\`
	}
	return `/`
}

// SlashUploadPath 从给定路径中提取指定Linux风格路径部分(统一转换为Linux路径地址)
func SlashUploadPath(path string, pfs ...string) string {
	prefix := `uploads`
	if len(pfs) > 0 {
		prefix = pfs[0]
	}
	re := regexp.MustCompile(fmt.Sprintf(`\/%s+[a-zA-Z0-9\/\.]*$`, prefix))
	return re.FindString(filepath.ToSlash(path))
}

// GenFilename 生成文件名
func GenFilename(fileExt string, names ...string) string {
	ext := filepath.Ext(fileExt) // 图片后缀
	if p := strings.IndexByte(ext, '?'); p != -1 {
		ext = fileExt[0:p]
	}

	// 初始化随机数
	rand.NewSource(time.Now().UnixNano())
	name := encrypt.NewM().MustEncryptString(
		fmt.Sprintf(`%s-%d`, fileExt, rand.Intn(9999999)),
	)

	// 其他参数
	if len(names) > 0 {
		for _, n := range names {
			name += n
		}
	}
	return fmt.Sprintf(`%s%s`, name, ext)
}

// UploadSubDir 设置上传附件路径
func UploadSubDir(dir string, isRoot bool) string {
	// 设置时间
	dir = strings.TrimRight(dir, "/") + DirSeparator() + gtime.Now().Format("Ymd")
	// 是否设置资源目录
	if isRoot {
		dir = RelaUploadPath(dir)
	}
	return strings.TrimRight(filepath.ToSlash(dir), `/`) + `/`
}

// 解析Base64前缀获取图片扩展
func ParseBase64ImageExt(baseExt string, filename ...string) (string, error) {
	imgExt := strings.Split(
		regexp.MustCompile(`image\/[a-zA-Z]+`).FindString(baseExt), `/`,
	)
	if len(imgExt) < 2 {
		return "", errors.New(`缺少图片Base64前缀`)
	}
	// 拼接文件名
	if len(filename) > 0 {
		return fmt.Sprintf(`%s.%s`, filename[0], imgExt[1]), nil
	}
	return `.` + imgExt[1], nil
}

// FilenameMd5 Md5文件名
func FilenameMd5(content string) string {
	if len(content) == 0 {
		return ""
	}
	return encrypt.NewM().MustEncryptString(content)
}
